home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ghostview / Path.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  18KB  |  946 lines

  1. /*
  2.  * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and its
  5.  * documentation for any purpose and without fee is hereby granted, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Software Research Associates not be used
  9.  * in advertising or publicity pertaining to distribution of the software
  10.  * without specific, written prior permission.  Software Research Associates
  11.  * makes no representations about the suitability of this software for any
  12.  * purpose.  It is provided "as is" without express or implied warranty.
  13.  *
  14.  * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  15.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  16.  * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  18.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  19.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20.  * PERFORMANCE OF THIS SOFTWARE.
  21.  *
  22.  * Author: Erik M. van der Poel
  23.  *         Software Research Associates, Inc., Tokyo, Japan
  24.  *         erik@sra.co.jp
  25.  */
  26.  
  27. #include <stdio.h>
  28.  
  29. #ifdef SEL_FILE_IGNORE_CASE
  30. #include <ctype.h>
  31. #endif /* def SEL_FILE_IGNORE_CASE */
  32.  
  33. #include <X11/Xos.h>
  34. #include <pwd.h>
  35. #include "SFinternal.h"
  36. #include "xstat.h"
  37. #include <X11/Xaw/Scrollbar.h>
  38.  
  39. #if defined(SVR4) || defined(SYSV) || defined(USG)
  40. extern uid_t getuid();
  41. extern void qsort();
  42. #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
  43.  
  44. typedef struct {
  45.     char    *name;
  46.     char    *dir;
  47. } SFLogin;
  48.  
  49. SFDir *SFdirs = NULL;
  50.  
  51. int SFdirEnd;
  52.  
  53. int SFdirPtr;
  54.  
  55. int SFbuttonPressed = 0;
  56.  
  57. static int SFdoNotTouchDirPtr = 0;
  58.  
  59. static int SFdoNotTouchVorigin = 0;
  60.  
  61. static SFDir SFrootDir, SFhomeDir;
  62.  
  63. static SFLogin *SFlogins;
  64.  
  65. static int SFtwiddle = 0;
  66.  
  67. int
  68. SFchdir(path)
  69.     char    *path;
  70. {
  71.     int    result;
  72.  
  73.     result = 0;
  74.  
  75.     if (strcmp(path, SFcurrentDir)) {
  76.         result = chdir(path);
  77.         if (!result) {
  78.             (void) strcpy(SFcurrentDir, path);
  79.         }
  80.     }
  81.  
  82.     return result;
  83. }
  84.  
  85. static
  86. SFfree(i)
  87.     int    i;
  88. {
  89.     register SFDir    *dir;
  90.     register int    j;
  91.  
  92.     dir = &(SFdirs[i]);
  93.  
  94.     for (j = dir->nEntries - 1; j >= 0; j--) {
  95.         if (dir->entries[j].shown != dir->entries[j].real) {
  96.             XtFree(dir->entries[j].shown);
  97.         }
  98.         XtFree(dir->entries[j].real);
  99.     }
  100.  
  101.     XtFree((char *) dir->entries);
  102.  
  103.     XtFree(dir->dir);
  104.  
  105.     dir->dir = NULL;
  106. }
  107.  
  108. static
  109. SFunreadableDir(dir)
  110.     SFDir    *dir;
  111. {
  112.     char    *cannotOpen = "<cannot open> ";
  113.  
  114.     dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
  115.     dir->entries[0].statDone = 1;
  116.     dir->entries[0].real = XtMalloc((unsigned) (strlen(cannotOpen) + 1));
  117.     (void) strcpy(dir->entries[0].real, cannotOpen);
  118.     dir->entries[0].shown = dir->entries[0].real;
  119.     dir->nEntries = 1;
  120.     dir->nChars = strlen(cannotOpen);
  121. }
  122.  
  123. #ifdef SEL_FILE_IGNORE_CASE
  124. static
  125. SFstrncmp(p, q, n)
  126.     register char    *p, *q;
  127.     register int    n;
  128. {
  129.     register char    c1, c2;
  130.     char        *psave, *qsave;
  131.     int        nsave;
  132.  
  133.     psave = p;
  134.     qsave = q;
  135.     nsave = n;
  136.  
  137.     c1 = *p++;
  138.     if (islower(c1)) {
  139.         c1 = toupper(c1);
  140.     }
  141.     c2 = *q++;
  142.     if (islower(c2)) {
  143.         c2 = toupper(c2);
  144.     }
  145.  
  146.     while ((--n >= 0) && (c1 == c2)) {
  147.         if (!c1) {
  148.             return strncmp(psave, qsave, nsave);
  149.         }
  150.         c1 = *p++;
  151.         if (islower(c1)) {
  152.             c1 = toupper(c1);
  153.         }
  154.         c2 = *q++;
  155.         if (islower(c2)) {
  156.             c2 = toupper(c2);
  157.         }
  158.     }
  159.  
  160.     if (n < 0) {
  161.         return strncmp(psave, qsave, nsave);
  162.     }
  163.  
  164.     return c1 - c2;
  165. }
  166. #endif /* def SEL_FILE_IGNORE_CASE */
  167.  
  168. static
  169. SFreplaceText(dir, str)
  170.     SFDir    *dir;
  171.     char    *str;
  172. {
  173.     int    len;
  174.  
  175.     *(dir->path) = 0;
  176.     len = strlen(str);
  177.     if (str[len - 1] == '/') {
  178.         (void) strcat(SFcurrentPath, str);
  179.     } else {
  180.         (void) strncat(SFcurrentPath, str, len - 1);
  181.     }
  182.     if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
  183.         SFsetText(SFcurrentPath);
  184.     } else {
  185.         SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
  186.     }
  187.  
  188.     SFtextChanged();
  189. }
  190.  
  191. static void
  192. SFexpand(str)
  193.     char    *str;
  194. {
  195.     int    len;
  196.     int    cmp;
  197.     char    *name, *growing;
  198.     SFDir    *dir;
  199.     SFEntry    *entry, *max;
  200.  
  201.     len = strlen(str);
  202.  
  203.     dir = &(SFdirs[SFdirEnd - 1]);
  204.  
  205.     if (dir->beginSelection == -1) {
  206.         str = strcpy(XtMalloc((unsigned) (strlen(str) + 1)), str);
  207.         SFreplaceText(dir, str);
  208.         XtFree(str);
  209.         return;
  210.     } else if (dir->beginSelection == dir->endSelection) {
  211.         SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
  212.         return;
  213.     }
  214.  
  215.     max = &(dir->entries[dir->endSelection + 1]);
  216.  
  217.     name = dir->entries[dir->beginSelection].shown;
  218.     (void) strcpy((growing = XtMalloc((unsigned) (strlen(name) + 1))),
  219.         name);
  220.  
  221.     cmp = 0;
  222.     while (!cmp) {
  223.         entry = &(dir->entries[dir->beginSelection]);
  224.         while (entry < max) {
  225.             if (cmp = strncmp(growing, entry->shown, len)) {
  226.                 break;
  227.             }
  228.             entry++;
  229.         }
  230.         len++;
  231.     }
  232.  
  233.     /*
  234.      * SFreplaceText() expects filename
  235.      */
  236.     growing[len - 2] = ' ';
  237.  
  238.     growing[len - 1] = 0;
  239.     SFreplaceText(dir, growing);
  240.     XtFree(growing);
  241. }
  242.  
  243. static int
  244. SFfindFile(dir, str)
  245.     SFDir        *dir;
  246.     register char    *str;
  247. {
  248.     register int    i, last, max;
  249.     register char    *name, save;
  250.     SFEntry        *entries;
  251.     int        len;
  252.     int        begin, end;
  253.     int        result;
  254.  
  255.     len = strlen(str);
  256.  
  257.     if (str[len - 1] == ' ') {
  258.         SFexpand(str);
  259.         return 1;
  260.     } else if (str[len - 1] == '/') {
  261.         len--;
  262.     }
  263.  
  264.     max = dir->nEntries;
  265.  
  266.     entries = dir->entries;
  267.  
  268.     i = 0;
  269.     while (i < max) {
  270.         name = entries[i].shown;
  271.         last = strlen(name) - 1;
  272.         save = name[last];
  273.         name[last] = 0;
  274.  
  275. #ifdef SEL_FILE_IGNORE_CASE
  276.         result = SFstrncmp(str, name, len);
  277. #else /* def SEL_FILE_IGNORE_CASE */
  278.         result = strncmp(str, name, len);
  279. #endif /* def SEL_FILE_IGNORE_CASE */
  280.  
  281.         name[last] = save;
  282.         if (result <= 0) {
  283.             break;
  284.         }
  285.         i++;
  286.     }
  287.     begin = i;
  288.     while (i < max) {
  289.         name = entries[i].shown;
  290.         last = strlen(name) - 1;
  291.         save = name[last];
  292.         name[last] = 0;
  293.  
  294. #ifdef SEL_FILE_IGNORE_CASE
  295.         result = SFstrncmp(str, name, len);
  296. #else /* def SEL_FILE_IGNORE_CASE */
  297.         result = strncmp(str, name, len);
  298. #endif /* def SEL_FILE_IGNORE_CASE */
  299.  
  300.         name[last] = save;
  301.         if (result) {
  302.             break;
  303.         }
  304.         i++;
  305.     }
  306.     end = i;
  307.  
  308.     if (begin != end) {
  309.         if (
  310.             (dir->beginSelection != begin) ||
  311.             (dir->endSelection != end - 1)
  312.         ) {
  313.             dir->changed = 1;
  314.             dir->beginSelection = begin;
  315.             if (str[strlen(str) - 1] == '/') {
  316.                 dir->endSelection = begin;
  317.             } else {
  318.                 dir->endSelection = end - 1;
  319.             }
  320.         }
  321.     } else {
  322.         if (dir->beginSelection != -1) {
  323.             dir->changed = 1;
  324.             dir->beginSelection = -1;
  325.             dir->endSelection = -1;
  326.         }
  327.     }
  328.  
  329.     if (
  330.         SFdoNotTouchVorigin ||
  331.         ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))
  332.     ) {
  333.         SFdoNotTouchVorigin = 0;
  334.         return 0;
  335.     }
  336.  
  337.     i = begin - 1;
  338.     if (i > max - SFlistSize) {
  339.         i = max - SFlistSize;
  340.     }
  341.     if (i < 0) {
  342.         i = 0;
  343.     }
  344.  
  345.     if (dir->vOrigin != i) {
  346.         dir->vOrigin = i;
  347.         dir->changed = 1;
  348.     }
  349.  
  350.     return 0;
  351. }
  352.  
  353. static
  354. SFunselect()
  355. {
  356.     SFDir    *dir;
  357.  
  358.     dir = &(SFdirs[SFdirEnd - 1]);
  359.     if (dir->beginSelection != -1) {
  360.         dir->changed = 1;
  361.     }
  362.     dir->beginSelection = -1;
  363.     dir->endSelection = -1;
  364. }
  365.  
  366. static int
  367. SFcompareLogins(p, q)
  368.     SFLogin    *p, *q;
  369. {
  370.     return strcmp(p->name, q->name);
  371. }
  372.  
  373. static
  374. SFgetHomeDirs()
  375. {
  376.     struct passwd    *pw;
  377.     struct stat    statBuf;
  378.     int        alloc;
  379.     int        i;
  380.     SFEntry        *entries = NULL;
  381. #ifndef    HOME_ON_DEMAND /* by Y.Kawabe */
  382.     int        len;
  383. #endif    /* HOME_ON_DEMAND */
  384.     int        maxChars;
  385.  
  386.     alloc = 0;
  387.     i = 0;
  388.  
  389.     maxChars = -1;
  390.  
  391.     if (pw = getpwuid((int) getuid())) {
  392.         if (
  393.             (!stat(pw->pw_dir, &statBuf)) &&
  394.             (S_ISDIR (statBuf.st_mode))
  395.         ) {
  396.             alloc = 1;
  397.             i = 1;
  398.             entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
  399.             SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
  400.             entries[0].real = XtMalloc(3);
  401.             (void) strcpy(entries[0].real, "~");
  402.             entries[0].shown = entries[0].real;
  403.             entries[0].statDone = 1;
  404.             SFlogins[0].name = "";
  405.             SFlogins[0].dir = XtMalloc((unsigned)
  406.                 (strlen(pw->pw_dir) + 1));
  407.             (void) strcpy(SFlogins[0].dir, pw->pw_dir);
  408.             maxChars = 1;
  409.         }
  410.     }
  411.  
  412. #ifndef    HOME_ON_DEMAND /* by Y.Kawabe */
  413.  
  414.     (void) setpwent();
  415.  
  416.     while ((pw = getpwent()) && (*(pw->pw_name))) {
  417.         if (
  418.             (!stat(pw->pw_dir, &statBuf)) &&
  419.             (S_ISDIR (statBuf.st_mode))
  420.         ) {
  421.             if (i >= alloc) {
  422.                 alloc *= 2;
  423.                 entries = (SFEntry *) XtRealloc(
  424.                     (char *) entries,
  425.                     (unsigned) (alloc * sizeof(SFEntry))
  426.                 );
  427.                 SFlogins = (SFLogin *) XtRealloc(
  428.                     (char *) SFlogins,
  429.                     (unsigned) (alloc * sizeof(SFLogin))
  430.                 );
  431.             }
  432.             len = strlen(pw->pw_name);
  433.             entries[i].real = XtMalloc((unsigned) (len + 3));
  434.             (void) strcat(strcpy(entries[i].real, "~"),
  435.                 pw->pw_name);
  436.             entries[i].shown = entries[i].real;
  437.             entries[i].statDone = 1;
  438.             if (len > maxChars) {
  439.                 maxChars = len;
  440.             }
  441.             SFlogins[i].name = XtMalloc((unsigned)
  442.                 (strlen(pw->pw_name) + 1));
  443.             (void) strcpy(SFlogins[i].name, pw->pw_name);
  444.             SFlogins[i].dir = XtMalloc((unsigned)
  445.                 (strlen(pw->pw_dir) + 1));
  446.             (void) strcpy(SFlogins[i].dir, pw->pw_dir);
  447.             i++;
  448.         }
  449.     }
  450.  
  451. #endif    /* HOME_ON_DEMAND */
  452.  
  453.     SFhomeDir.dir            = XtMalloc(1)    ;
  454.     SFhomeDir.dir[0]        = 0        ;
  455.     SFhomeDir.path            = SFcurrentPath    ;
  456.     SFhomeDir.entries        = entries    ;
  457.     SFhomeDir.nEntries        = i        ;
  458.     SFhomeDir.vOrigin        = 0        ;    /* :-) */
  459.     SFhomeDir.nChars        = maxChars + 2    ;
  460.     SFhomeDir.hOrigin        = 0        ;
  461.     SFhomeDir.changed        = 1        ;
  462.     SFhomeDir.beginSelection    = -1        ;
  463.     SFhomeDir.endSelection        = -1        ;
  464.  
  465. #if defined(SVR4) || defined(SYSV) || defined(USG)
  466.     qsort((char *) entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
  467.     qsort((char *) SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
  468. #else /* defined(SVR4) || defined(SYSV) || defined(USG) */
  469.     qsort((char *) entries, i, sizeof(SFEntry), SFcompareEntries);
  470.     qsort((char *) SFlogins, i, sizeof(SFLogin), SFcompareLogins);
  471. #endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
  472.  
  473.     for (i--; i >= 0; i--) {
  474.         (void) strcat(entries[i].real, "/");
  475.     }
  476. }
  477.  
  478.  
  479. static int
  480. SFfindHomeDir(begin, end)
  481.     char    *begin, *end;
  482. {
  483.     char    save;
  484.     char    *theRest;
  485.     int    i;
  486.  
  487.     save = *end;
  488.     *end = 0;
  489.  
  490.     for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
  491.         if (!strcmp(SFhomeDir.entries[i].real, begin)) {
  492.             *end = save;
  493.             theRest = XtMalloc((unsigned) (strlen(end) + 1));
  494.             (void) strcpy(theRest, end);
  495.             (void) strcat(strcat(strcpy(SFcurrentPath,
  496.                 SFlogins[i].dir), "/"), theRest);
  497.             XtFree(theRest);
  498.             SFsetText(SFcurrentPath);
  499.             SFtextChanged();
  500.             return 1;
  501.         }
  502.     }
  503.  
  504. #ifdef    HOME_ON_DEMAND /* by Y.Kawabe */
  505.     if (*(++begin)) {
  506.         struct passwd *pwd;
  507.         char user[256];
  508.         int i = 0;
  509.  
  510.         while (*begin && *begin != '/' && i < sizeof(user))
  511.             user[i++] = *begin++;
  512.         user[i] = '\0';
  513.  
  514.         if (pwd = getpwnam(user)) {
  515.             theRest = XtMalloc((unsigned) (strlen(end) + 1));
  516.             (void) strcpy(theRest, end);
  517.             (void) strcat(strcat(strcpy(SFcurrentPath,
  518.                 pwd->pw_dir), "/"), theRest);
  519.             XtFree(theRest);
  520.             SFsetText(SFcurrentPath);
  521.             SFtextChanged();
  522.             return 1;
  523.         }
  524.     }
  525. #endif    /* HOME_ON_DEMAND */
  526.  
  527.     *end = save;
  528.  
  529.     return 0;
  530. }
  531.  
  532. SFupdatePath()
  533. {
  534.     static int    alloc;
  535.     static int    wasTwiddle = 0;
  536.     char        *begin, *end;
  537.     int        i, j;
  538.     int        len;
  539.     int        prevChange;
  540.     int        SFdirPtrSave, SFdirEndSave;
  541.     SFDir        *dir;
  542.  
  543.     if (!SFdirs) {
  544.         SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
  545.         dir = &(SFdirs[0]);
  546.         dir->dir = XtMalloc(2);
  547.         (void) strcpy(dir->dir, "/");
  548.         (void) SFchdir("/");
  549.         (void) SFgetDir(dir);
  550.         for (j = 1; j < alloc; j++) {
  551.             SFdirs[j].dir = NULL;
  552.         }
  553.         dir->path = SFcurrentPath + 1;
  554.         dir->vOrigin = 0;
  555.         dir->hOrigin = 0;
  556.         dir->changed = 1;
  557.         dir->beginSelection = -1;
  558.         dir->endSelection = -1;
  559.         SFgetHomeDirs();
  560.     }
  561.  
  562.     SFdirEndSave = SFdirEnd;
  563.     SFdirEnd = 1;
  564.  
  565.     SFdirPtrSave = SFdirPtr;
  566.     SFdirPtr = 0;
  567.  
  568.     begin = NULL;
  569.  
  570.     if (SFcurrentPath[0] == '~') {
  571.         if (!SFtwiddle) {
  572.             SFtwiddle = 1;
  573.             dir = &(SFdirs[0]);
  574.             SFrootDir = *dir;
  575.             *dir = SFhomeDir;
  576.             dir->changed = 1;
  577.         }
  578.         end = SFcurrentPath;
  579.         SFdoNotTouchDirPtr = 1;
  580.         wasTwiddle = 1;
  581.     } else {
  582.         if (SFtwiddle) {
  583.             SFtwiddle = 0;
  584.             dir = &(SFdirs[0]);
  585.             *dir = SFrootDir;
  586.             dir->changed = 1;
  587.         }
  588.         end = SFcurrentPath + 1;
  589.     }
  590.  
  591.     i = 0;
  592.  
  593.     prevChange = 0;
  594.  
  595.     while (*end) {
  596.         while (*end++ == '/') {
  597.             ;
  598.         }
  599.         end--;
  600.         begin = end;
  601.         while ((*end) && (*end++ != '/')) {
  602.             ;
  603.         }
  604.         if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
  605.             SFdirPtr = i - 1;
  606.             if (SFdirPtr < 0) {
  607.                 SFdirPtr = 0;
  608.             }
  609.         }
  610.         if (*begin) {
  611.             if (*(end - 1) == '/') {
  612.                 char save = *end;
  613.  
  614.                 if (SFtwiddle) {
  615.                     if (SFfindHomeDir(begin, end)) {
  616.                         return;
  617.                     }
  618.                 }
  619.                 *end = 0;
  620.                 i++;
  621.                 SFdirEnd++;
  622.                 if (i >= alloc) {
  623.                     SFdirs = (SFDir *) XtRealloc(
  624.                         (char *) SFdirs,
  625.                         (unsigned) ((alloc *= 2) *
  626.                             sizeof(SFDir))
  627.                     );
  628.                     for (j = alloc / 2; j < alloc; j++) {
  629.                         SFdirs[j].dir = NULL;
  630.                     }
  631.                 }
  632.                 dir = &(SFdirs[i]);
  633.                 if (
  634.                     (!(dir->dir)) ||
  635.                     prevChange ||
  636.                     strcmp(dir->dir, begin)
  637.                 ) {
  638.                     if (dir->dir) {
  639.                         SFfree(i);
  640.                     }
  641.                     prevChange = 1;
  642.                     len = strlen(begin) + 1;
  643.                     dir->dir = XtMalloc((unsigned) len);
  644.                     (void) strcpy(dir->dir, begin);
  645.                     dir->path = end;
  646.                     dir->vOrigin = 0;
  647.                     dir->hOrigin = 0;
  648.                     dir->changed = 1;
  649.                     dir->beginSelection = -1;
  650.                     dir->endSelection = -1;
  651.                     (void) SFfindFile(dir - 1, begin);
  652.                     if (
  653.                         SFchdir(SFcurrentPath) ||
  654.                         SFgetDir(dir)
  655.                     ) {
  656.                         SFunreadableDir(dir);
  657.                         break;
  658.                     }
  659.                 }
  660.                 *end = save;
  661.                 if (!save) {
  662.                     SFunselect();
  663.                 }
  664.             } else {
  665.                 if (SFfindFile(&(SFdirs[SFdirEnd-1]), begin)) {
  666.                     return;
  667.                 }
  668.             }
  669.         } else {
  670.             SFunselect();
  671.         }
  672.     }
  673.  
  674.     if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
  675.         SFunselect();
  676.     }
  677.  
  678.     for (i = SFdirEnd; i < alloc; i++) {
  679.         if (SFdirs[i].dir) {
  680.             SFfree(i);
  681.         }
  682.     }
  683.  
  684.     if (SFdoNotTouchDirPtr) {
  685.         if (wasTwiddle) {
  686.             wasTwiddle = 0;
  687.             SFdirPtr = SFdirEnd - 2;
  688.             if (SFdirPtr < 0) {
  689.                 SFdirPtr = 0;
  690.             }
  691.         } else {
  692.             SFdirPtr = SFdirPtrSave;
  693.         }
  694.         SFdoNotTouchDirPtr = 0;
  695.     }
  696.  
  697.     if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
  698.         XawScrollbarSetThumb(
  699.             selFileHScroll,
  700.             (float) (((double) SFdirPtr) / SFdirEnd),
  701.             (float) (((double) ((SFdirEnd < 3) ? SFdirEnd : 3)) /
  702.                 SFdirEnd)
  703.         );
  704.     }
  705.  
  706.     if (SFdirPtr != SFdirPtrSave) {
  707.         SFdrawLists(SF_DO_SCROLL);
  708.     } else {
  709.         for (i = 0; i < 3; i++) {
  710.             if (SFdirPtr + i < SFdirEnd) {
  711.                 if (SFdirs[SFdirPtr + i].changed) {
  712.                     SFdirs[SFdirPtr + i].changed = 0;
  713.                     SFdrawList(i, SF_DO_SCROLL);
  714.                 }
  715.             } else {
  716.                 SFclearList(i, SF_DO_SCROLL);
  717.             }
  718.         }
  719.     }
  720. }
  721.  
  722. SFsetText(path)
  723.     char    *path;
  724. {
  725.     XawTextBlock    text;
  726.  
  727.     text.firstPos = 0;
  728.     text.length = strlen(path);
  729.     text.ptr = path;
  730.     text.format = FMT8BIT;
  731.  
  732.     XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
  733.     XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
  734. }
  735.  
  736. /* ARGSUSED */
  737. void
  738. SFbuttonPressList(w, n, event)
  739.     Widget            w;
  740.     int            n;
  741.     XButtonPressedEvent    *event;
  742. {
  743.     SFbuttonPressed = 1;
  744. }
  745.  
  746. /* ARGSUSED */
  747. void
  748. SFbuttonReleaseList(w, n, event)
  749.     Widget            w;
  750.     int            n;
  751.     XButtonReleasedEvent    *event;
  752. {
  753.     SFDir    *dir;
  754.  
  755.     SFbuttonPressed = 0;
  756.  
  757.     if (SFcurrentInvert[n] != -1) {
  758.         if (n < 2) {
  759.             SFdoNotTouchDirPtr = 1;
  760.         }
  761.         SFdoNotTouchVorigin = 1;
  762.         dir = &(SFdirs[SFdirPtr + n]);
  763.         SFreplaceText(
  764.             dir,
  765.             dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown
  766.         );
  767.         SFmotionList(w, n, event);
  768.     }
  769. }
  770.  
  771. static int
  772. SFcheckDir(n, dir)
  773.     int        n;
  774.     SFDir        *dir;
  775. {
  776.     struct stat    statBuf;
  777.     int        i;
  778.  
  779.     if (
  780.         (!stat(".", &statBuf)) &&
  781.         (statBuf.st_mtime != dir->mtime)
  782.     ) {
  783.  
  784.         /*
  785.          * If the pointer is currently in the window that we are about
  786.          * to update, we must warp it to prevent the user from
  787.          * accidentally selecting the wrong file.
  788.          */
  789.         if (SFcurrentInvert[n] != -1) {
  790.             XWarpPointer(
  791.                 SFdisplay,
  792.                 None,
  793.                 XtWindow(selFileLists[n]),
  794.                 0,
  795.                 0,
  796.                 0,
  797.                 0,
  798.                 0,
  799.                 0
  800.             );
  801.         }
  802.  
  803.         for (i = dir->nEntries - 1; i >= 0; i--) {
  804.             if (dir->entries[i].shown != dir->entries[i].real) {
  805.                 XtFree(dir->entries[i].shown);
  806.             }
  807.             XtFree(dir->entries[i].real);
  808.         }
  809.         XtFree((char *) dir->entries);
  810.         if (SFgetDir(dir)) {
  811.             SFunreadableDir(dir);
  812.         }
  813.         if (dir->vOrigin > dir->nEntries - SFlistSize) {
  814.             dir->vOrigin = dir->nEntries - SFlistSize;
  815.         }
  816.         if (dir->vOrigin < 0) {
  817.             dir->vOrigin = 0;
  818.         }
  819.         if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
  820.             dir->hOrigin = dir->nChars - SFcharsPerEntry;
  821.         }
  822.         if (dir->hOrigin < 0) {
  823.             dir->hOrigin = 0;
  824.         }
  825.         dir->beginSelection = -1;
  826.         dir->endSelection = -1;
  827.         SFdoNotTouchVorigin = 1;
  828.         if ((dir + 1)->dir) {
  829.             (void) SFfindFile(dir, (dir + 1)->dir);
  830.         } else {
  831.             (void) SFfindFile(dir, dir->path);
  832.         }
  833.  
  834.         if (!SFworkProcAdded) {
  835.             (void) XtAppAddWorkProc(SFapp, SFworkProc, NULL);
  836.             SFworkProcAdded = 1;
  837.         }
  838.  
  839.         return 1;
  840.     }
  841.  
  842.     return 0;
  843. }
  844.  
  845. static int
  846. SFcheckFiles(dir)
  847.     SFDir    *dir;
  848. {
  849.     int        from, to;
  850.     int        result;
  851.     char        old, new;
  852.     int        i;
  853.     char        *str;
  854.     int        last;
  855.     struct stat    statBuf;
  856.  
  857.     result = 0;
  858.  
  859.     from = dir->vOrigin;
  860.     to = dir->vOrigin + SFlistSize;
  861.     if (to > dir->nEntries) {
  862.         to = dir->nEntries;
  863.     }
  864.  
  865.     for (i = from; i < to; i++) {
  866.         str = dir->entries[i].real;
  867.         last = strlen(str) - 1;
  868.         old = str[last];
  869.         str[last] = 0;
  870.         if (stat(str, &statBuf)) {
  871.             new = ' ';
  872.         } else {
  873.             new = SFstatChar(&statBuf);
  874.         }
  875.         str[last] = new;
  876.         if (new != old) {
  877.             result = 1;
  878.         }
  879.     }
  880.  
  881.     return result;
  882. }
  883.  
  884. void
  885. SFdirModTimer()
  886. {
  887.     static int    n = -1;
  888.     static int    f = 0;
  889.     char        save;
  890.     SFDir        *dir;
  891.  
  892.     if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
  893.         n++;
  894.         if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) {
  895.             n = 0;
  896.             f++;
  897.             if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) {
  898.                 f = 0;
  899.             }
  900.         }
  901.         dir = &(SFdirs[SFdirPtr + n]);
  902.         save = *(dir->path);
  903.         *(dir->path) = 0;
  904.         if (SFchdir(SFcurrentPath)) {
  905.             *(dir->path) = save;
  906.  
  907.             /*
  908.              * force a re-read
  909.              */
  910.             *(dir->dir) = 0;
  911.  
  912.             SFupdatePath();
  913.         } else {
  914.             *(dir->path) = save;
  915.             if (
  916.                 SFcheckDir(n, dir) ||
  917.                 ((f == n) && SFcheckFiles(dir))
  918.             ) {
  919.                 SFdrawList(n, SF_DO_SCROLL);
  920.             }
  921.         }
  922.     }
  923.  
  924.     SFdirModTimerId = XtAppAddTimeOut(SFapp, (unsigned long) 1000,
  925.         SFdirModTimer, (XtPointer) NULL);
  926. }
  927.  
  928. /* Return a single character describing what kind of file STATBUF is.  */
  929.  
  930. char
  931. SFstatChar (statBuf)
  932.     struct stat *statBuf;
  933. {
  934.     if (S_ISDIR (statBuf->st_mode)) {
  935.         return '/';
  936.     } else if (S_ISREG (statBuf->st_mode)) {
  937.       return S_ISXXX (statBuf->st_mode) ? '*' : ' ';
  938. #ifdef S_ISSOCK
  939.     } else if (S_ISSOCK (statBuf->st_mode)) {
  940.         return '=';
  941. #endif /* S_ISSOCK */
  942.     } else {
  943.         return ' ';
  944.     }
  945. }
  946.